home *** CD-ROM | disk | FTP | other *** search
- (define-module (lang elisp primitives syntax)
- #:use-module (lang elisp internals evaluation)
- #:use-module (lang elisp internals fset)
- #:use-module (lang elisp internals lambda)
- #:use-module (lang elisp internals set)
- #:use-module (lang elisp internals trace)
- #:use-module (lang elisp transform))
-
- ;;; Define Emacs Lisp special forms as macros. This is more flexible
- ;;; than handling them specially in the translator: allows them to be
- ;;; redefined, and hopefully allows better source location tracking.
-
- ;;; {Variables}
-
- (define (setq exp env)
- (cons begin
- (let loop ((sets (cdr exp)))
- (if (null? sets)
- '()
- (cons `(,set (,quote ,(car sets)) ,(transformer (cadr sets)))
- (loop (cddr sets)))))))
-
- (fset 'setq
- (procedure->memoizing-macro setq))
-
- (fset 'defvar
- (procedure->memoizing-macro
- (lambda (exp env)
- (trc 'defvar (cadr exp))
- (if (null? (cddr exp))
- `(,quote ,(cadr exp))
- `(,begin (,if (,not (,defined? (,quote ,(cadr exp))))
- ,(setq (list (car exp) (cadr exp) (caddr exp)) env))
- (,quote ,(cadr exp)))))))
-
- (fset 'defconst
- (procedure->memoizing-macro
- (lambda (exp env)
- (trc 'defconst (cadr exp))
- `(,begin ,(setq (list (car exp) (cadr exp) (caddr exp)) env)
- (,quote ,(cadr exp))))))
-
- ;;; {lambda, function and macro definitions}
-
- (fset 'lambda
- (procedure->memoizing-macro
- (lambda (exp env)
- (transform-lambda/interactive exp '<elisp-lambda>))))
-
- (fset 'defun
- (procedure->memoizing-macro
- (lambda (exp env)
- (trc 'defun (cadr exp))
- `(,begin (,fset (,quote ,(cadr exp))
- ,(transform-lambda/interactive (cdr exp)
- (symbol-append '<elisp-defun:
- (cadr exp)
- '>)))
- (,quote ,(cadr exp))))))
-
- (fset 'interactive
- (procedure->memoizing-macro
- (lambda (exp env)
- (fluid-set! interactive-spec exp)
- #f)))
-
- (fset 'defmacro
- (procedure->memoizing-macro
- (lambda (exp env)
- (trc 'defmacro (cadr exp))
- (call-with-values (lambda () (parse-formals (caddr exp)))
- (lambda (required optional rest)
- (let ((num-required (length required))
- (num-optional (length optional)))
- `(,begin (,fset (,quote ,(cadr exp))
- (,procedure->memoizing-macro
- (,lambda (exp1 env1)
- (,trc (,quote using) (,quote ,(cadr exp)))
- (,let* ((%--args (,cdr exp1))
- (%--num-args (,length %--args)))
- (,cond ((,< %--num-args ,num-required)
- (,error "Wrong number of args (not enough required args)"))
- ,@(if rest
- '()
- `(((,> %--num-args ,(+ num-required num-optional))
- (,error "Wrong number of args (too many args)"))))
- (else (,transformer
- (, @bind ,(append (map (lambda (i)
- (list (list-ref required i)
- `(,list-ref %--args ,i)))
- (iota num-required))
- (map (lambda (i)
- (let ((i+nr (+ i num-required)))
- (list (list-ref optional i)
- `(,if (,> %--num-args ,i+nr)
- (,list-ref %--args ,i+nr)
- ,%nil))))
- (iota num-optional))
- (if rest
- (list (list rest
- `(,if (,> %--num-args
- ,(+ num-required
- num-optional))
- (,list-tail %--args
- ,(+ num-required
- num-optional))
- ,%nil)))
- '()))
- ,@(map transformer (cdddr exp)))))))))))))))))
-
- ;;; {Sequencing}
-
- (fset 'progn
- (procedure->memoizing-macro
- (lambda (exp env)
- `(,begin ,@(map transformer (cdr exp))))))
-
- (fset 'prog1
- (procedure->memoizing-macro
- (lambda (exp env)
- `(,let ((%--res1 ,(transformer (cadr exp))))
- ,@(map transformer (cddr exp))
- %--res1))))
-
- (fset 'prog2
- (procedure->memoizing-macro
- (lambda (exp env)
- `(,begin ,(transformer (cadr exp))
- (,let ((%--res2 ,(transformer (caddr exp))))
- ,@(map transformer (cdddr exp))
- %--res2)))))
-
- ;;; {Conditionals}
-
- (fset 'if
- (procedure->memoizing-macro
- (lambda (exp env)
- (let ((else-case (cdddr exp)))
- (cond ((null? else-case)
- `(,nil-cond ,(transformer (cadr exp)) ,(transformer (caddr exp)) ,%nil))
- ((null? (cdr else-case))
- `(,nil-cond ,(transformer (cadr exp))
- ,(transformer (caddr exp))
- ,(transformer (car else-case))))
- (else
- `(,nil-cond ,(transformer (cadr exp))
- ,(transformer (caddr exp))
- (,begin ,@(map transformer else-case)))))))))
-
- (fset 'and
- (procedure->memoizing-macro
- (lambda (exp env)
- (cond ((null? (cdr exp)) #t)
- ((null? (cddr exp)) (transformer (cadr exp)))
- (else
- (cons nil-cond
- (let loop ((args (cdr exp)))
- (if (null? (cdr args))
- (list (transformer (car args)))
- (cons (list not (transformer (car args)))
- (cons %nil
- (loop (cdr args))))))))))))
-
- ;;; NIL-COND expressions have the form:
- ;;;
- ;;; (nil-cond COND VAL COND VAL ... ELSEVAL)
- ;;;
- ;;; The CONDs are evaluated in order until one of them returns true
- ;;; (in the Elisp sense, so not including empty lists). If a COND
- ;;; returns true, its corresponding VAL is evaluated and returned,
- ;;; except if that VAL is the unspecified value, in which case the
- ;;; result of evaluating the COND is returned. If none of the COND's
- ;;; returns true, ELSEVAL is evaluated and its value returned.
-
- (define <-- *unspecified*)
-
- (fset 'or
- (procedure->memoizing-macro
- (lambda (exp env)
- (cond ((null? (cdr exp)) %nil)
- ((null? (cddr exp)) (transformer (cadr exp)))
- (else
- (cons nil-cond
- (let loop ((args (cdr exp)))
- (if (null? (cdr args))
- (list (transformer (car args)))
- (cons (transformer (car args))
- (cons <--
- (loop (cdr args))))))))))))
-
- (fset 'cond
- (procedure->memoizing-macro
- (lambda (exp env)
- (if (null? (cdr exp))
- %nil
- (cons
- nil-cond
- (let loop ((clauses (cdr exp)))
- (if (null? clauses)
- (list %nil)
- (let ((clause (car clauses)))
- (if (eq? (car clause) #t)
- (cond ((null? (cdr clause)) (list #t))
- ((null? (cddr clause))
- (list (transformer (cadr clause))))
- (else `((,begin ,@(map transformer (cdr clause))))))
- (cons (transformer (car clause))
- (cons (cond ((null? (cdr clause)) <--)
- ((null? (cddr clause))
- (transformer (cadr clause)))
- (else
- `(,begin ,@(map transformer (cdr clause)))))
- (loop (cdr clauses)))))))))))))
-
- (fset 'while
- (procedure->memoizing-macro
- (lambda (exp env)
- `((,letrec ((%--while (,lambda ()
- (,nil-cond ,(transformer (cadr exp))
- (,begin ,@(map transformer (cddr exp))
- (%--while))
- ,%nil))))
- %--while)))))
-
- ;;; {Local binding}
-
- (fset 'let
- (procedure->memoizing-macro
- (lambda (exp env)
- `(, @bind ,(map (lambda (binding)
- (trc 'let binding)
- (if (pair? binding)
- `(,(car binding) ,(transformer (cadr binding)))
- `(,binding ,%nil)))
- (cadr exp))
- ,@(map transformer (cddr exp))))))
-
- (fset 'let*
- (procedure->memoizing-macro
- (lambda (exp env)
- (if (null? (cadr exp))
- `(,begin ,@(map transformer (cddr exp)))
- (car (let loop ((bindings (cadr exp)))
- (if (null? bindings)
- (map transformer (cddr exp))
- `((, @bind (,(let ((binding (car bindings)))
- (if (pair? binding)
- `(,(car binding) ,(transformer (cadr binding)))
- `(,binding ,%nil))))
- ,@(loop (cdr bindings)))))))))))
-
- ;;; {Exception handling}
-
- (fset 'unwind-protect
- (procedure->memoizing-macro
- (lambda (exp env)
- (trc 'unwind-protect (cadr exp))
- `(,let ((%--throw-args #f))
- (,catch #t
- (,lambda ()
- ,(transformer (cadr exp)))
- (,lambda args
- (,set! %--throw-args args)))
- ,@(map transformer (cddr exp))
- (,if %--throw-args
- (,apply ,throw %--throw-args))))))
-